#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

typedef enum
{
    E_OPT_READ,
    E_OPT_WRITE,
} E_OPT;

#define BUF_LEN 16
// 堆缓冲区溢出-读
void heap_overflow_read()
{
    char *heap_buf = (char *)calloc(1, BUF_LEN);
    char ret = *(heap_buf + BUF_LEN * 2);
    free(heap_buf);
}

// 2.堆缓冲区溢出-写
void heap_overflow_write()
{
    char *heap_buf = (char *)calloc(1, BUF_LEN);
    *(heap_buf + BUF_LEN + 2) = 'r';
    memcpy(heap_buf + 30, "overflow", 8);
    free(heap_buf);
}

// 3.栈缓冲区溢出-读
void stack_overflow_read()
{
    printf("3.栈缓冲区溢出-读\n");
    uint8_t buf[16] = {0};
    uint8_t stack_buf[4] = {0};
    memcpy(stack_buf, buf, sizeof(buf));
}

// 4.栈缓冲区溢出-写
void stack_overflow_write()
{
    printf("4.栈缓冲区溢出-写\n");
    char stack_buf[4] = {0};
    strcpy(stack_buf, "12345678");
}

// 5.访问空指针
void access_free_point()
{
    printf("5.使用空指针\n");
    char *p = (char *)malloc(BUF_LEN);
    free(p);

    char a = p[1];
}

// 6.内存泄漏
void manual_leak_mem(void)
{
    printf("申请3次内存，少释放一次,主动触发 内存泄漏\n");
    int *p_data[3];
    p_data[0] = malloc(sizeof(int));
    p_data[1] = malloc(sizeof(int) * 3);
    p_data[2] = malloc(sizeof(int) * 5);

    free(p_data[0]);
    // free(p_data[1]);
    // free(p_data[2]);
}

// 7.内存泄漏
void mem_leak(void)
{
    printf("主动触发 内存泄漏\n");
    char *p = malloc(BUF_LEN);
    // free(p);
}

// 8,9 全局变量-缓冲区溢出
int x[20];
void global_overflow(E_OPT opt)
{
    int y;
    if (opt == E_OPT_READ)
        y = x[20];
    else if (opt == E_OPT_WRITE)
        x[20] = 5;
}

// 10,11,12 strncat strcpy memcpy内存重叠
void strncat_param_overlap(int cmd)
{
    char buffer[] = "hello\0XXX";
    if(cmd == 10)
        strncat(buffer, buffer + 1, 3); // BOOM
    else if(cmd == 11)
        strncpy(buffer, buffer + 1, 5);
    else if(cmd == 12)
        memcpy(buffer, buffer + 1, 5);
    return;
}

int main(int argc, char **argv)
{
    int cmd = 6;
    if (argc > 1)
        cmd = atoi(argv[1]);

    switch (cmd)
    {
    case 1:
        heap_overflow_read();
        break;
    case 2:
        heap_overflow_write();
        break;
    case 3:
        stack_overflow_read();
        break;
    case 4:
        stack_overflow_write();
        break;
    case 5:
        access_free_point();
        break;
    case 6:
        manual_leak_mem();
        break;
    case 7:
        mem_leak();
        break;
    case 8:
        global_overflow(E_OPT_READ);
        break;
    case 9:
        global_overflow(E_OPT_WRITE);
        break;
    case 10:
    case 11:
    case 12:
        strncat_param_overlap(cmd);
        break;
    default:
        break;
    };

    return 0;
}
